之前在單例模式時有提過,使用懶漢式
的方式在定義單例模式時,有可能會發生線程不安全的問題。
class Bank {
private static Bank instance;
private Bank() {}
public static Bank getInstance() {
synchronized(Bank.class) {
if(instance == null) {
instance = new Bank();
}
return instance;
}
}
}
透過synchronized
可以避免發生多個線程時,創建了兩個Bank
的實例。
線程間的通信指的是,當不同的線程需要共同完成某一項任務時,透過通信的方式,讓他們能夠按照規律的方式執行,而不會產生非預期的狀況發生。
可以透過等待
、喚醒
、喚醒全部
三個方法去進行這樣的操作
wait()
:當線程執行到wait()
時,會進入等待
狀態,並且將鎖
釋放。notify()
:當線程執行到notify()
時,會喚醒等待
狀態中優先級最高
的線程,若優先級相同會隨機喚醒其中一個線程,被喚醒
的線程會從進入等待狀態時的程式碼繼續執行。notifyAll()
:當線程執行到notifyAll()
時會喚醒所有等待
狀態中的線程。// 要使用兩個線程交互印出1-100的數字
class PrintNumber implements Runnable {
private int number = 1;
@Override
public void run() {
synchronized(this) {
// 須注意必須和鎖為同一個物件
this.notify();
while(true) {
if(number <= 100) {
System.out.println(Thread.currentThread().getName() + ":" + i);
number++;
} else {
break;
}
try {
// 須注意必須和鎖為同一個物件
this.wait();
} catch(InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
使用這三個方法時需要注意幾個點
synchronized
方法或同步塊中使用。synchronized
使用的鎖
為同一個
物件,若不相同會有IllegalMonitorStateException
異常。Object
類中。